# -*- coding: utf-8 -*-

__author__="Hugo Poloni"
__date__ ="$02/12/2009 14:26:07$"

import os
import re
import sys

from PyQt4 import QtCore, QtGui, QtXml
from rarfile import RarFile

import libLTV

class RlsStatus():
    QUEUED = 1
    SEARCHING = 2
    DOWNLOADING = 3
    FINISHED = 4
    NOT_AVAILABLE = 5
    ERROR = 6

class RlsTreeWidgetItem(QtGui.QTreeWidgetItem):
    def __init__(self, filepath):
        self.series_re = re.compile('(?P<series_name>.+?)\.(?P<episode>(s|S)\d{2}(e|E)\d{2}|\d{3-4}).+-(?P<rls_group>.+?)(\..+| .+|$)')

        self.subs = []
        if not self._tv_series_input(filepath):
            raise ValueError(filepath)

        QtGui.QTreeWidgetItem.__init__(self,[self.rls,'',self.folder])
        self.setStatus(RlsStatus.QUEUED)

    def setStatus(self, status):

        color = None
        text = None

        if status == RlsStatus.QUEUED:
            color = QtCore.Qt.yellow
            text = 'Queued'
        elif status == RlsStatus.SEARCHING:
            color = QtCore.Qt.lightGray
            text = 'Searching'
        elif status == RlsStatus.DOWNLOADING:
            color = QtCore.Qt.gray
            text = 'Downloading'
        elif status == RlsStatus.FINISHED:
            color = QtCore.Qt.green
            text = 'Finished'
        elif status == RlsStatus.NOT_AVAILABLE:
            color = QtCore.Qt.red
            text = 'No Subtitle Available'
        elif status == RlsStatus.ERROR:
            color = QtCore.Qt.black
            text = 'Error'
        else:
            color = QtCore.Qt.black
            text = 'DEFAULT ERROR!!!!!'

        self.setBackgroundColor(1, color)
        self.setText(1, text)

    def _tv_series_input(self, filepath):
        #TODO: save extra info as REPACK, NUKED
        abs_path = os.path.abspath(filepath)
        folder, filename = os.path.split(abs_path)

        re_match = self.series_re.match(filename)
        if re_match:
            self.rls = os.path.splitext(filename)[0]
        else:
            re_match = self.series_re.match(folder)
            if re_match:
                self.rls = folder.upper()
            else:
                return False

        self.folder = folder
        self.rls_name = re_match.group('series_name').upper()
        self.rls_group = re_match.group('rls_group').upper()

        series_number = re_match.group('episode')
        if series_number.isdigit():
            if len(series_number) == 3:
                self.ep_info = 's0' + series_number[0] + 'e' + series_number[1:]
            else: # len == 4
                self.ep_info = 's' + series_number[:1] + 'e' + series_number[1:]
        else:
            self.ep_info = series_number.upper()

        self.query = ' '.join((self.rls_name, self.ep_info, self.rls_group))

        return True

    def _movie_input(self, folder, filename):
        pass

    def insert_subs(self, items):
        self.subs = items

    def get_prefered_sub(self):
        #choose between most downloaded/oficial group/best note
        try:
            r = self.subs[0][0]
            return r
        except IndexError:
            return None

class LsDPreferenceDialog(QtGui.QDialog):

    def __init__(self, config={}, parent=None):
        QtGui.QDialog.__init__(self, parent)

        self._parse_config(config)

        login_group_box = QtGui.QGroupBox('Login')
        login_layout = QtGui.QGridLayout()

        lable_username = QtGui.QLabel('Username:')
        self.input_username = QtGui.QLineEdit(self.config['username'])
        self.input_username.setMaxLength(20)
        lable_password = QtGui.QLabel('Password:')
        self.input_password = QtGui.QLineEdit(self.config['password'])
        self.input_password.setMaxLength(20)
        self.input_password.setEchoMode(QtGui.QLineEdit.Password)

        login_layout.addWidget(lable_username,0,0)
        login_layout.addWidget(self.input_username,0,1)
        login_layout.addWidget(lable_password,1,0)
        login_layout.addWidget(self.input_password,1,1)

        login_group_box.setLayout(login_layout)

        dir_group_box = QtGui.QGroupBox(u'Diretorios')
        dir_layout = QtGui.QGridLayout()

        rar_checkbox = QtGui.QLabel('Salvar arquivos".rar"s em:')

        self.store_folder = QtGui.QLineEdit(self.config['store_folder'])
        rar_dir_button = QtGui.QPushButton('...')
        rar_dir_button.setFixedSize(40,20)

        dir_layout.addWidget(rar_checkbox,0,0)
        dir_layout.addWidget(self.store_folder,1,0)
        dir_layout.addWidget(rar_dir_button,1,1)

        dir_group_box.setLayout(dir_layout)

        button_box = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)

        vbox = QtGui.QVBoxLayout()

        vbox.addWidget(login_group_box)
        vbox.addWidget(dir_group_box)
        vbox.addWidget(button_box)

        self.connect(rar_dir_button, QtCore.SIGNAL('clicked()'), self._select_store_folder)
        self.connect(button_box, QtCore.SIGNAL('accepted()'), self._create_config_file);
        self.connect(button_box, QtCore.SIGNAL('rejected()'), self, QtCore.SLOT('reject()'));
        self.setLayout(vbox)
        self.resize(300,250)
        self.setWindowTitle(u'LsD - Preferencias')
        self.setModal(True)

    def _parse_config(self, config):
        self.config = {'username':'','password':''}

        file_path = os.path.abspath(sys.argv[0])
        folder = os.path.split(file_path)[0]

        self.config['store_folder'] = folder

        for k, v in config.iteritems():
            self.config[k] = v

    def _create_config_file(self):
        config_file = QtCore.QFile('ltv.config')

        if not config_file.open(QtCore.QFile.WriteOnly):
            print 'Erro ao gravar arquivo'
            return False

        doc = QtXml.QDomDocument()
        root = doc.createElement('ltv_config');
        doc.appendChild(root);

        node_user = doc.createElement('username');
        root.appendChild(node_user);
        login_value = doc.createTextNode(self.input_username.text());
        node_user.appendChild(login_value);

        node_pass = doc.createElement('password');
        root.appendChild(node_pass);
        password_value = doc.createTextNode(self.input_password.text());
        node_pass.appendChild(password_value);

        node_store_folder = doc.createElement('store_folder');
        root.appendChild(node_store_folder);
        folder_value = doc.createTextNode(self.store_folder.text());
        node_store_folder.appendChild(folder_value);

        config_file.writeData(doc.toString())
        config_file.close()

        self.done(1)

    def _select_store_folder(self):
        store_folder = QtGui.QFileDialog.getExistingDirectory(self, u'Selecione um diretorio')
        if store_folder:
            norm__store_folder = os.path.abspath(store_folder)
            self.store_folder.setText(norm__store_folder)

class LsD(QtGui.QMainWindow):

    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)

        self._create_main_window()
        self._create_actions()
        self._create_menubar()
        self._create_toolbar()
        self.setStatusBar(QtGui.QStatusBar())

        self.config = {}
        self.show()
        while not self._read_config_file():
            self._dialog_preference()

        self.ltv = libLTV.LibLTV(self.config['username'],self.config['password'],self.config['store_folder'])
        self.rls_pending = {}

        self._create_connections()

    def _create_connections(self):
        
        self.connect(self.ltv, QtCore.SIGNAL('downloadFinished(id, filepath)'), self._download_finished)
        self.connect(self.ltv, QtCore.SIGNAL('searchFinished(id, items)'), self._search_finished)
        self.connect(self.rls_tree, QtCore.SIGNAL('itemSelectionChanged ()'), self._rls_selection_changed)

        self.connect(self.add_action, QtCore.SIGNAL('triggered()'), self._dialog_add_file)
        self.connect(self.remove_action, QtCore.SIGNAL('triggered()'), self._remove_rls_item)
        self.connect(self.exit_action, QtCore.SIGNAL('triggered()'), self.close)
        self.connect(self.pref_action, QtCore.SIGNAL('triggered()'), self._dialog_preference)
        
    def _dialog_preference(self):
        self.dlg_pref = LsDPreferenceDialog(self.config, parent=self)
        if self.dlg_pref.exec_():
            self._read_config_file()

    def _read_config_file(self):

        config_file = QtCore.QFile('ltv.config')
        if not config_file.open(QtCore.QFile.ReadOnly):
            return False

        doc = QtXml.QDomDocument()
        doc.setContent(config_file)

        self.config = {}

        self.config['username'] =  str(doc.elementsByTagName('username').item(0).toElement().text())
        self.config['password'] =  str(doc.elementsByTagName('password').item(0).toElement().text())
        self.config['store_folder'] =  str(doc.elementsByTagName('store_folder').item(0).toElement().text())

        config_file.close()
        return True

    def _create_actions(self):

        self.add_action = QtGui.QAction('Adicionar',self)
        self.remove_action = QtGui.QAction('Remover',self)
        self.exit_action = QtGui.QAction('Sair',self)
        self.about_action = QtGui.QAction('Sobre',self)
        self.pref_action = QtGui.QAction(u'Preferencias',self)

    def _create_menubar(self):

        menubar = QtGui.QMenuBar()
        self.setMenuBar(menubar)

        m_file = menubar.addMenu('Arquivo')
        m_file.addAction(self.add_action)
        m_file.addAction(self.remove_action)
        m_file.addSeparator()
        m_file.addAction(self.exit_action)

        m_option = menubar.addMenu(u'Opcoes')
        m_option.addAction(self.pref_action)

        m_help = menubar.addMenu('Ajuda')
        m_help.addAction(self.about_action)

    def _create_toolbar(self):
        toolbar = QtGui.QToolBar('Toolbar Area')
        toolbar.setMovable(False)
        self.addToolBar(toolbar)

        toolbar.addAction(self.add_action)
        toolbar.addAction(self.remove_action)

    def _search_finished(self, id, items):
        item = self.rls_pending.pop(id)
        item.insert_subs(items)
        sub_code = item.get_prefered_sub()
        if sub_code:
            item.setStatus(RlsStatus.DOWNLOADING)
            id  = self.ltv.download_sub(sub_code)
            self.rls_pending[id] = item
        else:
            item.setStatus(RlsStatus.NOT_AVAILABLE)

    def _download_finished(self, id, filepath):
        item = self.rls_pending.pop(id)
        if self._extract_sub(filepath, item):
            item.setStatus(RlsStatus.FINISHED)
        else:
            item.setStatus(RlsStatus.ERROR)

    def _extract_sub(self, filepath, item, preferred_type='.SRT'):
        #Test for zip files...

        try:
            archive = RarFile(filepath)
        except:
            print 'Erro ao abrir o arquivo rar'
            return False
        else:
            folder = item.folder
            rls_group = item.rls_group

            files = archive.namelist()

            srt_sub = []
            ass_sub = []

            for filename in files:
                p_file = filename.upper()
                if p_file.find(rls_group) > -1:
                    if p_file.endswith('.SRT'):
                        srt_sub.append(filename)
                    elif p_file.endswith('.ASS'):
                        ass_sub.append(filename)

            out = None
            if preferred_type == '.SRT' and len(srt_sub) > 0:
                out = srt_sub
            elif  preferred_type == '.SRT' and len(ass_sub) > 0:
                out = ass_sub
            elif  preferred_type == '.ASS' and len(ass_sub) > 0:
                out = ass_sub
            elif  preferred_type == '.ASS' and len(srt_sub) > 0:
                out = srt_sub
            else:
                #error - no subtitle
                pass

            if out:
                for filename in out:
                    p_file = filename.upper()
                    filepath = os.path.join(folder, filename)
                    f = open(filepath,'w')
                    try:
                        f.write(archive.read(filename))
                    except Exception:
                        return False
                    f.close()
                item.setStatus(RlsStatus.FINISHED)
            else:
                item.setStatus(RlsStatus.ERROR)

            return True

    def _rls_selection_changed(self):
        self.sub_tree.clear()
        items = self.rls_tree.selectedItems()
        if len(items) == 1:
            item = items[0]
            for sub in item.subs:
                self.sub_tree.addTopLevelItem(QtGui.QTreeWidgetItem([sub[0],sub[1], sub[2]]))
        else:
            #show message??
            print 'multiplos itens selecionados.. o q fazer??'

    def _dialog_add_file(self):

        filepath = QtGui.QFileDialog.getOpenFileName(
                         self,
                         u'Selecione um arquivo de video',
                         '',
                         u'Video (*.avi *.mkv *.wmv)')
        if filepath:
            item = None
            try:
                item = RlsTreeWidgetItem(filepath)
            except ValueError as e:
                text = 'Erro ao adicionar o seguinte arquivo:\n' + str(e)
                QtGui.QMessageBox( QtGui.QMessageBox.Warning,'Erro', text, QtGui.QMessageBox.Ok, self).open()
            else:
                self.rls_tree.addTopLevelItem(item)
                item.setStatus(1)
                id = self.ltv.search(item.query)
                self.rls_pending[id] = item

    def _remove_rls_item(self):
                items = self.rls_tree.selectedItems()
                for item in items:
                    self.rls_tree.removeItemWidget(item,0)

    def _create_main_window(self):
        main_w = QtGui.QWidget()

        hbox = QtGui.QHBoxLayout()
        hbox.setContentsMargins(0,0,0,0)

        h_splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
        h_splitter.setChildrenCollapsible(False)
        v_splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
        v_splitter.setChildrenCollapsible(False)

        status_tree = QtGui.QTreeWidget()
        status_tree.setHeaderHidden(True)
        status_tree.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        status_tree.setMinimumSize(10,0)
        status_tree.setEnabled(False)

        status_tree.addTopLevelItem(QtGui.QTreeWidgetItem(['Todos']))
        status_tree.addTopLevelItem(QtGui.QTreeWidgetItem(['Baixando']))
        status_tree.addTopLevelItem(QtGui.QTreeWidgetItem(['Finalizado']))
        status_tree.addTopLevelItem(QtGui.QTreeWidgetItem(['Esperando']))
        status_tree.addTopLevelItem(QtGui.QTreeWidgetItem(['Erro']))

        self.rls_tree = QtGui.QTreeWidget()
        self.rls_tree.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
        self.rls_tree.setHeaderLabels(['Release','Status','Pasta'])
        self.rls_tree.setSortingEnabled(True)

        self.sub_tree = QtGui.QTreeWidget()
        self.sub_tree.setHeaderLabels(['Release','Downloads','Nota','Enviado por'])

        h_splitter.addWidget(status_tree)
        h_splitter.addWidget(v_splitter)

        h_splitter.setStretchFactor(0,0)
        h_splitter.setStretchFactor(1,1)
        h_splitter.setSizes([125,0])

        v_splitter.addWidget(self.rls_tree)
        v_splitter.addWidget(self.sub_tree)

        v_splitter.setStretchFactor(0,1)
        v_splitter.setStretchFactor(1,0)
        v_splitter.setSizes([0,100])

        hbox.addWidget(h_splitter)
        main_w.setLayout(hbox)
        self.setWindowTitle('LsD - Legendas.TV Downloader')
        self.setCentralWidget(main_w)
        self.resize(900,500)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    main = LsD()
    main.show()
    sys.exit(app.exec_())